package com.fwtai.tool;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * 二维码生成
 * @作者 田应平
 * @版本 v1.0
 * @创建时间 2021-09-14 17:05
 * @QQ号码 444141300
 * @Email service@dwlai.com
 * @官网 http://www.fwtai.com
*/
public class ToolZxing{

    private static final int BLACK = 0xFF000000;
    private static final int WHITE = 0xFFFFFFFF;

    private static final int DEFAULT_HEIGHT = 300;// 二维码图片宽度
    private static final int DEFAULT_WIDTH = 300;// 二维码图片高度
    private static final String DEFAULT_FORMAT = "gif";// 二维码的图片格式

    private static final int BARCODE_HEIGHT = 30;
    private static final int BARCODE_WIDTH = 150;
    private static final String BARCODE_FORMAT = "png";

    /**
     * 生成二维码 到指定 路径
     * @param outputStream 到指定 路径 、FILE
     * @param text 可以是网址 和 其他，网址就是跳转
     * @throws WriterException
     * @throws IOException
     */
    public static void encode2DCode(OutputStream outputStream, String text)
        throws WriterException, IOException {
        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); // 内容所使用字符集编码
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(text,BarcodeFormat.QR_CODE, DEFAULT_WIDTH, DEFAULT_HEIGHT, hints);
        BufferedImage image = toBufferedImage(bitMatrix);
        /*
         * Graphics2D gs = image.createGraphics(); //载入logo Image img =
         * ImageIO.read(new File(srcImagePath)); gs.drawImage(img, 125, 125,
         * null); gs.dispose(); img.flush();
         */
        if (!ImageIO.write(image, DEFAULT_FORMAT, outputStream)) {
            throw new IOException("Could not write an image of format "  + DEFAULT_FORMAT + " to stream");
        }
    }

    /**
     * 返回BitMatrix二维码内容
     * @param text
     * @return
     * @throws WriterException
     */
    public static BitMatrix encode2DCode(String text) throws WriterException {
        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); // 内容所使用字符集编码
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(text,BarcodeFormat.QR_CODE, DEFAULT_WIDTH, DEFAULT_HEIGHT, hints);
        return bitMatrix;
    }

    /**
     *
     * @param outputFile 到指定路径
     * @param text 可以是网址 和 其他内容，网址就是跳转
     * @param width 二维码 宽度
     * @param height 二维码高度
     * @param format 生成二维码的图片格式
     * @throws WriterException
     * @throws IOException
     */
    public static void encode2DCode(File outputFile, String text, int width,int height, String format) throws WriterException, IOException {
        // 读取源图像
        Map<EncodeHintType, String> hints = new HashMap<EncodeHintType, String>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); // 内容所使用字符集编码
        BitMatrix bitMatrix = new MultiFormatWriter().encode(text,BarcodeFormat.QR_CODE, width, height, hints);
        writeToFile(bitMatrix, format, outputFile);
    }

    /**
     * 生成条码号
     * <p>2017年1月17日 下午1:56:33
     * <p>create by hjc
     * @throws WriterException
     * @throws IOException
     */
    public static void encodeBarcode(File outputFile, String text) throws WriterException, IOException{
        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        //      hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); // 内容所使用字符集编码
        //      hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(text,
            BarcodeFormat.CODE_128, BARCODE_WIDTH, BARCODE_HEIGHT, hints);
        writeToFile(bitMatrix, BARCODE_FORMAT, outputFile);
    }


    public static BufferedImage toBufferedImage(BitMatrix matrix) throws IOException {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }

    public static void writeToFile(BitMatrix matrix, String format, File file,String srcImagePath)
        throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        Graphics2D gs = image.createGraphics(); //载入logo
        Image img = ImageIO.read(new File(srcImagePath));
        gs.drawImage(img, 125, 125, null);
        gs.dispose();
        img.flush();
        if (!ImageIO.write(image, format, file)) {
            throw new IOException("Could not write an image of format " + format + " to " + file);
        }
    }

    public static void writeToFile(BitMatrix matrix, String format, File file)
        throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        /*
         * Graphics2D gs = image.createGraphics(); //载入logo Image img =
         * ImageIO.read(new File(srcImagePath)); gs.drawImage(img, 125, 125,
         * null); gs.dispose(); img.flush();
         */
        if (!ImageIO.write(image, format, file)) {
            throw new IOException("Could not write an image of format " + format + " to " + file);
        }
    }

    public static void writeToStream(BitMatrix matrix, String format,
                                     OutputStream stream) throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, stream)) {
            throw new IOException("Could not write an image of format " + format);
        }
    }

    /**
     * 把传入的原始图像按高度和宽度进行缩放，生成符合要求的图标
     *
     * @param srcImageFile 源文件地址
     * @param height 目标高度
     * @param width 目标宽度
     * @param hasFiller 比例不对时是否需要补白：true为补白; false为不补白;
     * @throws IOException
     */
    @SuppressWarnings("unused")
    private static BufferedImage scale(String srcImageFile, int height,
                                       int width, boolean hasFiller) throws IOException {
        double ratio = 0.0; // 缩放比例
        File file = new File(srcImageFile);
        BufferedImage srcImage = ImageIO.read(file);
        Image destImage = srcImage.getScaledInstance(width, height,
            BufferedImage.SCALE_SMOOTH);
        // 计算比例
        if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) {
            if (srcImage.getHeight() > srcImage.getWidth()) {
                ratio = (new Integer(height)).doubleValue()
                    / srcImage.getHeight();
            } else {
                ratio = (new Integer(width)).doubleValue()
                    / srcImage.getWidth();
            }
            AffineTransformOp op = new AffineTransformOp(
                AffineTransform.getScaleInstance(ratio, ratio), null);
            destImage = op.filter(srcImage, null);
        }
        if (hasFiller) {// 补白
            BufferedImage image = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
            Graphics2D graphic = image.createGraphics();
            graphic.setColor(Color.white);
            graphic.fillRect(0, 0, width, height);
            if (width == destImage.getWidth(null))
                graphic.drawImage(destImage, 0,
                    (height - destImage.getHeight(null)) / 2,
                    destImage.getWidth(null), destImage.getHeight(null),
                    Color.white, null);
            else
                graphic.drawImage(destImage,
                    (width - destImage.getWidth(null)) / 2, 0,
                    destImage.getWidth(null), destImage.getHeight(null),
                    Color.white, null);
            graphic.dispose();
            destImage = image;
        }
        return (BufferedImage) destImage;
    }

    public static void scale(String srcImageFile, String result, int scale, boolean flag) {
        try {
            BufferedImage src = ImageIO.read(new File(srcImageFile)); // 读入文件
            int width = src.getWidth(); // 得到源图宽
            int height = src.getHeight(); // 得到源图长
            if (flag) {
                // 放大
                width = width * scale;
                height = height * scale;
            } else {
                // 缩小
                width = width / scale;
                height = height / scale;
            }
            Image image = src.getScaledInstance(width, height,
                Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            g.drawImage(image, 0, 0, null); // 绘制缩小后的图
            g.dispose();
            ImageIO.write(tag, "JPEG", new File(result));// 输出到文件流
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}